package com.x.provider.general.service.cms;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.x.core.web.page.PageDomain;
import com.x.core.web.page.PageHelper;
import com.x.core.web.page.PageList;
import com.x.provider.api.general.enums.TopicSourceTypeEnum;
import com.x.provider.api.general.model.dto.cms.TopicListReqDTO;
import com.x.provider.general.configure.GeneralConfig;
import com.x.provider.general.mapper.TopicFavoriteMapper;
import com.x.provider.general.mapper.TopicMapper;
import com.x.provider.general.model.domain.cms.Topic;
import com.x.provider.general.model.domain.cms.TopicFavorite;
import com.x.provider.general.model.query.cms.TopicQuery;
import com.x.util.ChineseCharToEnUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TopicServiceImpl implements TopicService {

    private final TopicMapper topicMapper;
    private final GeneralConfig applicationConfig;
    private final TopicFavoriteMapper topicFavoriteMapper;

    public TopicServiceImpl(TopicMapper topicMapper,
                            GeneralConfig applicationConfig,
                            TopicFavoriteMapper topicFavoriteMapper){
        this.topicMapper = topicMapper;
        this.applicationConfig = applicationConfig;
        this.topicFavoriteMapper = topicFavoriteMapper;
    }


    @Override
    public List<Topic> searchTopic(String keyword){
        var query = new LambdaQueryWrapper<Topic>();
        if (StringUtils.hasText(keyword)) {
            query.like(Topic::getSearchKeyWord, keyword);
        }
        query.orderByDesc(Topic::getEffectValue).last(StrUtil.format(" limit {}", applicationConfig.getTopSearchResultLimit()));
        return topicMapper.selectList(query);
    }

    @Override
    public Optional<Topic> getTopic(Long id, String title) {
        LambdaQueryWrapper<Topic> query = build(TopicQuery.builder().id(id).title(title).build());
        return Optional.ofNullable(topicMapper.selectOne(query));
    }

    private LambdaQueryWrapper<Topic> build(TopicQuery query) {
        var queryWrapper = new LambdaQueryWrapper<Topic>();
        if (query.getId() != null) {
            queryWrapper.eq(Topic::getId, query.getId());
        }
        if (!StringUtils.isEmpty(query.getTitle())){
            queryWrapper.eq(Topic::getTitle, query.getTitle());
        }
        if (!CollectionUtils.isEmpty(query.getTitleList())){
            queryWrapper.in(Topic::getTitle, query.getTitleList());
        }
        if (!CollectionUtils.isEmpty(query.getIdList())){
            queryWrapper.in(Topic::getId, query.getIdList());
        }
        return queryWrapper;
    }

    @Override
    public List<Topic> listTopic(List<String> titles, Integer itemType) {
        var query = new LambdaQueryWrapper<Topic>();
        query.in(Topic::getTitle, titles);
        return topicMapper.selectList(query);
    }

    @Override
    @Transactional
    public List<Topic> listOrCreateTopics(List<String> topicTitles, Integer itemType){
        List<Topic> result = listTopic(TopicQuery.builder().titleList(topicTitles).itemType(itemType).build());
        List<String> existedTopicTitles = result.stream().map(Topic::getTitle).collect(Collectors.toList());
        List<Topic> needCreateTopics = new ArrayList<>();
        topicTitles.stream().filter(item -> !existedTopicTitles.contains(item)).forEach(item -> {
            Topic topic = Topic.builder().searchKeyWord(StrUtil.format("{},{}", item, getFirstLetter(item))).effectValue(0)
                    .sourceType(TopicSourceTypeEnum.CUSTOMER_CUSTOMIZE.ordinal()).itemType(itemType).systemTopic(false).title(item).sourceId("0").build();
            topicMapper.insert(topic);
            result.add(topic);
            needCreateTopics.add(topic);
        });
        if (!needCreateTopics.isEmpty()){
//            List<TopicEvent> topicChangedEventList = new ArrayList<>(needCreateTopics.size());
//            needCreateTopics.forEach(item -> {
//                TopicEvent topicChangedEvent = BeanUtil.prepare(item, TopicEvent.class);
//                topicChangedEvent.setEventType(TopicEvent.EventTypeEnum.ADD.getValue());
//                topicChangedEventList.add(topicChangedEvent);
//            });
//            kafkaTemplate.send(VideoEventTopic.TOPIC_NAME_TOPIC_CHANGED_BATCH, TopicEvent.EventTypeEnum.ADD.getValue().toString(), TopicBatchEvent.builder()
//                    .topicEventList(topicChangedEventList).build());
        }
        final Map<String, Topic> topicResultMap = result.stream().collect(Collectors.toMap(item -> item.getTitle(), item -> item));
        List<Topic> orderedTopicResult = new ArrayList<>();
        topicTitles.forEach(item -> {
            orderedTopicResult.add(topicResultMap.get(item));
        });
        return result;
    }

    @Override
    public void favoriteTopic(Long customerId, Long topicId, Boolean favorite) {
        Optional<Topic> topic = getTopic(topicId, null);
        if (topic.isEmpty()){
            return;
        }
        Optional<TopicFavorite> topicCustomerFavorite = getTopicCustomerFavorite(customerId, topicId);
        if (topicCustomerFavorite.isPresent()){
            if (topicCustomerFavorite.get().getFavorite().equals(!favorite)){
                topicFavoriteMapper.updateById(TopicFavorite.builder().id(topicCustomerFavorite.get().getId()).favorite(favorite).build());
            }
            return;
        }
        topicFavoriteMapper.insert(TopicFavorite.builder()
                .favorite(favorite)
                .customerId(customerId)
                .topicSourceType(topic.get().getSourceType())
                .topicId(topicId)
                .build());
    }

    @Override
    public Boolean isFavoriteTopic(Long customerId, Long topicId) {
        if (customerId <= 0){
            return false;
        }
        Optional<TopicFavorite> topicCustomerFavorite = getTopicCustomerFavorite(customerId, topicId);
        if (topicCustomerFavorite.isPresent() && topicCustomerFavorite.get().getFavorite()){
            return true;
        }
        return false;
    }

    @Override
    public List<TopicFavorite> listTopicCustomerFavorite(Long customerId, TopicSourceTypeEnum topicSourceTypeEnum) {
        return topicFavoriteMapper.selectList(buildQuery(customerId, 0L, topicSourceTypeEnum == null ? null : topicSourceTypeEnum.ordinal(), true));
    }

    @Override
    public List<Topic> listTopic(TopicListReqDTO listTopicAO) {
        LambdaQueryWrapper query = buildQuery(listTopicAO.getIdList());
        return topicMapper.selectList(query);
    }

    @Override
    public PageList<Topic> listTopic(Long customerId, PageDomain pageDomain) {
        LambdaQueryWrapper<TopicFavorite> query = buildQuery(customerId, 0L, null, true).orderByDesc(TopicFavorite::getId)
                .last(StrUtil.format(" limit {} ", pageDomain.getPageSize()));
        if (pageDomain.getCursor() > 0){
            query.lt(TopicFavorite::getId, pageDomain.getCursor());
        }
        List<TopicFavorite> topicCustomerFavorites = topicFavoriteMapper.selectList(query);
        if (topicCustomerFavorites.isEmpty()){
            return new PageList<>();
        }
        TopicListReqDTO listTopicAO = TopicListReqDTO.builder().idList(topicCustomerFavorites.stream().map(TopicFavorite::getTopicId).collect(Collectors.toList())).build();
        Map<Long, Topic> topics = listTopic(listTopicAO).stream().collect(Collectors.toMap(Topic::getId, item -> item));
        return PageHelper.buildPageList(pageDomain.getPageSize(), CollectionUtils.lastElement(topicCustomerFavorites).getId(), topicCustomerFavorites, (t) -> topics.get(t.getTopicId()));
    }

    private Optional<TopicFavorite> getTopicCustomerFavorite(Long customerId, Long topicId){
        return Optional.ofNullable(topicFavoriteMapper.selectOne(buildQuery(customerId, topicId, null, null)));
    }

    private LambdaQueryWrapper<TopicFavorite> buildQuery(long customerId, long topicId, Integer topicSourceType, Boolean favorite){
        LambdaQueryWrapper<TopicFavorite> query = new LambdaQueryWrapper<>();
        if (customerId >0){
            query = query.eq(TopicFavorite::getCustomerId, customerId);
        }
        if (topicId > 0){
            query = query.eq(TopicFavorite::getTopicId, topicId);
        }
        if (topicSourceType != null){
            query = query.eq(TopicFavorite::getTopicSourceType, topicSourceType);
        }
        if (favorite != null){
            query = query.eq(TopicFavorite::getFavorite, favorite);
        }
        return query;
    }


    private String getFirstLetter(String source){
        try {
            return ChineseCharToEnUtils.getAllFirstLetter(source);
        }
        catch (UnsupportedEncodingException e){
            log.error(e.getMessage(), e);
            return source;
        }
    }

    private LambdaQueryWrapper buildQuery(List<Long> idList){
        LambdaQueryWrapper<Topic> query = new LambdaQueryWrapper<>();
        if (!CollectionUtils.isEmpty(idList)){
            query = query.in(Topic::getId, idList);
        }
        return query;
    }

    private List<Topic> listTopic(TopicQuery topicQuery){
        return topicMapper.selectList(build(topicQuery));
    }
}
